!> author: 左志华
!> date: 2022-05-26
!>
!> Time functions <br>
!> 时间
module master_time_m

    implicit none
    private

    public :: tic, toc, now, is_leap, bench

    integer, save :: time_save !! save the time

contains

    !> Start timer <br>
    !> 启动计时器
    impure subroutine tic()
        call system_clock(time_save)
    end subroutine tic

    !> Stop timer and return the time <br>
    !> 停止计时器并返回时间（秒计时）
    impure subroutine toc(t)
        class(*), optional :: t     !! time in seconds <br>
                                    !! 时间（秒计时）
        integer :: time_now, time_rate

        call system_clock(time_now, time_rate)

        associate (dt => real(time_now - time_save)/time_rate)

            if (present(t)) then
                select type (t)
                type is (real)
                    t = dt
                type is (double precision)
                    t = real(dt, 8)
                type is (integer)
                    t = nint(dt)
                type is (character(*))
                    write (*, "(2a,g0.3,a)") t, ', time elapsed: ', dt, " s"
                class default
                    write (*, '(a)') 'Error: unknown type of t in toc()'
                end select
            else
                write (*, "(a,g0.3,a)") 'Time elapsed: ', dt, " s"
            end if

        end associate

    end subroutine toc

    !> Get current time <br>
    !> 获得当前日期或时间
    impure character(23) function now() result(t)
        character(len=8) :: datstr
        character(len=10) :: timstr

        call date_and_time(datstr, timstr)

        t = datstr(1:4)//"-"// &
            datstr(5:6)//"-"// &
            datstr(7:8)//" "// &
            timstr(1:2)//":"// &
            timstr(3:4)//":"// &
            timstr(5:10)

    end function now

    !> Check if the year is leap year <br>
    !> 判断是否为闰年
    logical pure function is_leap(year)
        integer, intent(in) :: year !! the year to be checked <br>
                                    !! 检查的年份

        is_leap = (mod(year, 4) == 0 .and. mod(year, 100) /= 0) .or. mod(year, 400) == 0

    end function is_leap

    !> Bench my code <br>
    !> 测试代码性能
    impure subroutine bench(func, N, msg)
        external :: func
        integer, intent(in), optional :: N              !! the number of times to run the code <br>
                                                        !! 执行代码的次数
        character(len=*), intent(in), optional :: msg   !! the message to be printed <br>
                                                        !! 打印的消息
        integer :: Nx, i

        if (present(N)) then
            Nx = N
        else
            Nx = 10000
        end if

        call tic()
        do i = 1, N
            call func()
        end do

        if (present(msg)) then
            call toc(msg)
        else
            call toc()
        end if

    end subroutine bench

end module master_time_m
